﻿using System.IO;
using System.IO.Compression;
using System.Net;
using System.Text;
using System.Web;

namespace MediaWikiEditor.MediaWikiAccess
{
   /// <summary>
   /// Common data for media wiki access.
   /// </summary>
   public static class Common
   {
      /// <summary>
      /// Web request content type.
      /// </summary>
      public const string ContentType = "application/x-www-form-urlencoded";

      /// <summary>
      /// Name of user agent for web requests.
      /// </summary>
      public const string UserAgent = "MediaWikiAccess";

      /// <summary>
      /// POST data tag.
      /// </summary>
      public const string Post = "POST";
      
      /// <summary>
      /// Successful result.
      /// </summary>
      public const string ResultSuccess = "Success";

      /// <summary>
      /// The amount of time to retry things like requests.
      /// </summary>
      public const int TimesToRetry = 3;

      /// <summary>
      /// Gets the login url for the given site.
      /// </summary>
      /// <param name="site">Site to get url for.</param>
      /// <returns>Requested url.</returns>
      public static string LoginUrl (string site)
      {
         return string.Format ("{0}/api.php?action=login&format=json", site.TrimEnd ('/'));
      }

      /// <summary>
      /// Gets the url for the site information.
      /// </summary>
      /// <param name="site">Site to get url for.</param>
      /// <returns>Requested url.</returns>
      public static string SiteInfoUrl (string site)
      {
         return string.Format ("{0}/api.php?action=query&meta=siteinfo&format=json", site.TrimEnd ('/'));
      }

      /// <summary>
      /// Gets the url for querying page data.
      /// </summary>
      /// <param name="site">Site to get url for.</param>
      /// <param name="page">Page to query for.</param>
      /// <returns>Requested url.</returns>
      public static string QueryPageDataUrl (string site, string page)
      {
         return string.Format ("{0}/api.php?action=query&prop=revisions|categories|links|templates&pllimit=max&cllimit=max&tllimit=max&rvlimit=1&rvprop=timestamp|user|comment|content&format=json&indexpageids&titles={1}",
            site.TrimEnd ('/'), HttpUtility.UrlEncode(page));
      }

      /// <summary>
      /// Gets the url for querying a page's categories.
      /// </summary>
      /// <param name="site">Site to get url for.</param>
      /// <param name="page">Page to query for.</param>
      /// <returns>Requested url.</returns>
      public static string QueryCategoriesUrl (string site, string page)
      {
         return string.Format ("{0}/api.php?action=query&titles={1}&format=json&indexpageids&prop=categories",
            site.TrimEnd ('/'), HttpUtility.UrlEncode (page));
      }

      /// <summary>
      /// Gets the url for querying a page's links.
      /// </summary>
      /// <param name="site">Site to get url for.</param>
      /// <param name="page">Page to query for.</param>
      /// <returns>Requested url.</returns>
      public static string QueryLinksUrl (string site, string page)
      {
         return string.Format ("{0}/api.php?action=query&titles={1}&format=json&indexpageids&prop=links",
            site.TrimEnd ('/'), HttpUtility.UrlEncode (page));
      }

      /// <summary>
      /// Gets the url for querying a page's templates.
      /// </summary>
      /// <param name="site">Site to get url for.</param>
      /// <param name="page">Page to query for.</param>
      /// <returns>Requested url.</returns>
      public static string QueryTemplatesUrl (string site, string page)
      {
         return string.Format ("{0}/api.php?action=query&titles={1}&format=json&indexpageids&prop=templates",
            site.TrimEnd ('/'), HttpUtility.UrlEncode (page));
      }

      /// <summary>
      /// Gets the url for querying a page's templates.
      /// </summary>
      /// <param name="site">Site to get url for.</param>
      /// <param name="page">Page to query for.</param>
      /// <returns>Requested url.</returns>
      public static string QueryEditInfoUrl (string site, string page)
      {
         return string.Format ("{0}/api.php?action=query&prop=info&intoken=edit&format=json&indexpageids&titles={1}",
            site.TrimEnd ('/'), HttpUtility.UrlEncode (page));
      }

      /// <summary>
      /// Gets the url for editing a page.
      /// </summary>
      /// <param name="site">Site to get url for.</param>
      /// <param name="page">Page to query for.</param>
      /// <returns>Requested url.</returns>
      public static string EditPageUrl (string site, string page)
      {
         return string.Format ("{0}/api.php?action=edit&format=json&indexpageids&title={1}",
            site.TrimEnd ('/'), HttpUtility.UrlEncode (page));
      }

      /// <summary>
      /// Gets the url that lists all the pages.
      /// </summary>
      /// <param name="site">Site to get url for.</param>
      /// <param name="queryContinue">Query Continue data, if any.</param>
      /// <returns>Requested url.</returns>
      public static string AllPagesUrl (string site, string queryContinue = "")
      {
         return string.Format ("{0}/api.php?action=query&generator=allpages&gaplimit=500&format=json&indexpageids{1}",
            site.TrimEnd ('/'), (!string.IsNullOrEmpty (queryContinue) ? "&" + queryContinue : ""));
      }

      /// <summary>
      /// Gets the respons stream for the given response decompressing it if needed.
      /// </summary>
      /// <param name="webResponse">Web response to get stream for.</param>
      /// <returns>Requested stream with no compression.</returns>
      public static Stream GetWebResponseStream (HttpWebResponse webResponse)
      {
         var responseStream = webResponse.GetResponseStream ();
         string contentEncoding = webResponse.ContentEncoding.ToLower ();
         if (contentEncoding.Contains ("gzip"))
            responseStream = new GZipStream (responseStream, CompressionMode.Decompress);
         else if (contentEncoding.Contains ("deflate"))
            responseStream = new DeflateStream (responseStream, CompressionMode.Decompress);
         return responseStream;
      }

      /// <summary>
      /// Creates a default web request for the given url.
      /// </summary>
      /// <param name="url">Url to create web request for.</param>
      /// <returns>Requested WebRequest.</returns>
      public static HttpWebRequest CreateDefaultWebRequest (string url)
      {
         var webRequest = (HttpWebRequest)WebRequest.Create (url);
         webRequest.Proxy.Credentials = CredentialCache.DefaultCredentials;
         webRequest.UseDefaultCredentials = true;
         webRequest.ContentType = ContentType;
         webRequest.UserAgent = UserAgent;
         return webRequest;
      }

      /// <summary>
      /// Posts the given data.
      /// </summary>
      /// <param name="postData">Data to post.</param>
      /// <param name="webRequest">Webrequest to use in posting.</param>
      public static void PostData (string postData, WebRequest webRequest)
      {
         webRequest.Method = Post;
         var bytesToPost = Encoding.UTF8.GetBytes (postData);
         int bytesToPostLength = bytesToPost.Length;
         webRequest.ContentLength = bytesToPostLength;
         using (var requestStream = webRequest.GetRequestStream ())
            requestStream.Write (bytesToPost, 0, bytesToPostLength);
      }
   }
}
